"""
批量游戏运行器
专门用于输出关键事件和游戏结果，不包含可视化界面

作者：GitHub Copilot
版本：1.0 - 专注于事件输出和统计分析
"""

import sys
import os
import json
import time
import argparse
from typing import Dict, List, Tuple, Any
sys.path.insert(0, sys.path[0]+"/../")

from sh15.core.config import GameConfig
from sh15.core.CoreEnvironment import CoreEnvironment
from sh15.agents.fsm_defense_agent import create_fsm_defense_agent
from sh15.agents.simple_black_agent import SimpleBlackAgent
from sh15.agents.base_agent import AgentObservation
from sh15.agents.action_executor import ActionExecutor
from sh15.core.LockingSystem import LockingSystem
import numpy as np
import contextlib
import io


class TestCaseLoader:
    """测试案例加载器（无 GUI 依赖）"""
    def __init__(self, test_cases_dir: str):
        self.test_cases_dir = test_cases_dir

    def load_case(self, case_file: str) -> Dict[str, Any]:
        file_path = os.path.join(self.test_cases_dir, case_file)
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
        return {
            'case_name': case_file.replace('.json', ''),
            'black_boat_count': data.get('usvNum', 0),
            'black_boat_paths': {k: v for k, v in data.items() if k.startswith('usv') and k != 'usvNum'}
        }

    def load_all_cases(self) -> List[Dict[str, Any]]:
        if not os.path.isdir(self.test_cases_dir):
            return []
        files = [f for f in os.listdir(self.test_cases_dir) if f.endswith('.json') and '任务区域' not in f]
        # 尝试按“方案X-”中的 X 排序
        def get_case_number(name: str) -> int:
            try:
                prefix = name.split('-')[0]
                return int(prefix.replace('方案', ''))
            except Exception:
                return -1
        files.sort(key=get_case_number)
        return [self.load_case(f) for f in files]


class TestCaseBlackAgent:
    """测试集黑方智能体：按路径点驱动，并维护黑方锁定状态机"""
    def __init__(self, test_case_config: Dict[str, Any]):
        self.config = test_case_config
        self.boat_paths: Dict[int, List[Dict[str, Any]]] = {}
        self.boat_current_target: Dict[int, int] = {}

    def reset(self):
        self.boat_paths.clear()
        self.boat_current_target.clear()

    def initialize_paths(self, black_boats: List[Any]):
        for i, boat in enumerate(black_boats):
            usv_key = f"usv{i+1}"
            if usv_key in self.config.get('black_boat_paths', {}):
                self.boat_paths[boat.id] = self.config['black_boat_paths'][usv_key]
                self.boat_current_target[boat.id] = 0
                # 将初始位置对齐到路径首点
                if self.boat_paths[boat.id]:
                    first_point = self.boat_paths[boat.id][0]["point"]
                    boat.x = first_point[0]
                    boat.y = first_point[1]
                    boat.speed = self.boat_paths[boat.id][0]["speed"]

    def update_all_black_boats(self, core_env: CoreEnvironment, dt: float):
        current_time = core_env.current_time
        for boat in core_env.black_boats:
            if not boat.active or boat.is_frozen(current_time):
                continue
            if boat.id not in self.boat_paths:
                continue
            # 路径机动
            self._update_boat_path(boat, core_env.white_boats, dt)
            # 探测与锁定尝试（不改变机动，仅状态维护）
            LockingSystem.update_black_boat_detection(boat, core_env.white_boats)
            core_env.try_black_boat_lock(boat.id)

    def _update_boat_path(self, boat: Any, white_boats: List[Any], dt: float):
        path = self.boat_paths[boat.id]
        cur_idx = self.boat_current_target[boat.id]
        if cur_idx >= len(path):
            return
        target_point = path[cur_idx]
        target_x, target_y = target_point["point"]
        target_speed = target_point["speed"]

        dx = target_x - boat.x
        dy = target_y - boat.y
        distance = float(np.sqrt(dx*dx + dy*dy))

        if distance < target_speed * dt * 2:
            self.boat_current_target[boat.id] += 1
            if self.boat_current_target[boat.id] < len(path):
                next_point = path[self.boat_current_target[boat.id]]
                target_x, target_y = next_point["point"]
                target_speed = next_point["speed"]
                dx = target_x - boat.x
                dy = target_y - boat.y
                distance = float(np.sqrt(dx*dx + dy*dy))

        if distance > 0:
            direction_x = dx / distance
            direction_y = dy / distance
            boat.speed = min(target_speed, GameConfig.BLACK_BOAT_MAX_SPEED)
            boat.heading = float(np.arctan2(direction_y, direction_x))
            move_distance = boat.speed * dt
            boat.x += direction_x * move_distance
            boat.y += direction_y * move_distance


class GameEventTracker:
    """游戏事件跟踪器"""
    
    def __init__(self):
        self.events = []
        self.drone_launch_times = {}
        self.drone_landing_times = {}
        self.detection_events = []
        self.interception_events = []
        self.collision_events = []
        self.drone_interception_events = []
        
    def log_event(self, time: float, event_type: str, details: Dict[str, Any]):
        """记录游戏事件"""
        self.events.append({
            'time': time,
            'type': event_type,
            'details': details
        })
        
        # 按类型分类存储
        if event_type == 'drone_launch':
            self.drone_launch_times[details['drone_id']] = time
        elif event_type == 'drone_landing':
            self.drone_landing_times[details['drone_id']] = time
        elif event_type == 'detection':
            self.detection_events.append((time, details))
        elif event_type == 'interception':
            self.interception_events.append((time, details))
        elif event_type == 'collision':
            self.collision_events.append((time, details))
        elif event_type == 'drone_interception':
            self.drone_interception_events.append((time, details))
    
    def get_summary(self) -> Dict[str, Any]:
        """获取事件摘要"""
        return {
            'total_events': len(self.events),
            'drone_launches': len(self.drone_launch_times),
            'drone_landings': len(self.drone_landing_times),
            'detections': len(self.detection_events),
            'interceptions': len(self.interception_events),
            'collisions': len(self.collision_events),
            'drone_interceptions': len(self.drone_interception_events)
        }


class BatchGameRunner:
    """批量游戏运行器"""
    
    def __init__(self, use_fsm_agent=False, verbose=True):
        """初始化运行器"""
        self.core_env = CoreEnvironment()
        

        self.white_agent = create_fsm_defense_agent()
        self.agent_type = "FSM防御智能体"

        self.black_agent = SimpleBlackAgent()
        self.action_executor = ActionExecutor()
        self.event_tracker = GameEventTracker()
        self.verbose = verbose
        
        # 关闭调试输出以提高性能
        self.action_executor.set_debug_mode(False)
        GameConfig.debug_mode = False
        
        self.total_steps = 0
        self.max_steps = 50000  # 最大步数限制，防止无限循环
        
        # 测试集相关
        self.using_test_case = False
        # 仅输出关键摘要，屏蔽过程性打印
        self.summary_only = False
        
    def run_single_game(self) -> Dict[str, Any]:
        """运行单局游戏并返回结果"""
        start_time = time.time()
        
        # 重置环境和智能体
        self.core_env.reset()
        self.white_agent.reset()
        self.black_agent.reset()
        self.event_tracker = GameEventTracker()
        self.total_steps = 0
        
        if self.verbose:
            print(f"\n=== 开始新游戏 - {self.agent_type} ===")
            print(f"白方无人艇: {len(self.core_env.white_boats)}艘")
            print(f"黑方无人艇: {len(self.core_env.black_boats)}艘")
            print("-" * 50)
        
        # 记录初始状态
        initial_black_count = len([b for b in self.core_env.black_boats if b.active])
        
        # 游戏主循环
        while self.total_steps < self.max_steps:
            dt = GameConfig.TIME_STEP
            
            # 1. 更新探测系统
            self.core_env.update_detection_system()
            
            # 2. 记录探测事件
            # 从无人艇和无人机的视角收集所有被探测到的目标
            all_detected_ids = set()
            for boat in self.core_env.white_boats:
                if boat.active:
                    for target in boat.detected_targets:
                        if target.active:
                            all_detected_ids.add(target.id)
            for drone in self.core_env.all_white_drones:
                if drone.active and (getattr(drone, 'state', None) in ['flying', 'returning']):
                    for target in drone.detected_targets:
                        if target.active:
                            all_detected_ids.add(target.id)

            if all_detected_ids:
                self.event_tracker.log_event(
                    self.core_env.current_time,
                    'detection',
                    {'detected_black_boats': list(all_detected_ids)}
                )
            
            # 3. 白方AI决策和动作执行
            # 仅传入“当前帧被探测到”的黑方目标，避免越权获取真实坐标
            detected_ids = set()
            for boat in self.core_env.white_boats:
                for t in boat.detected_targets:
                    if t.active:
                        detected_ids.add(t.id)
            for drone in self.core_env.all_white_drones:
                for t in drone.detected_targets:
                    if t.active:
                        detected_ids.add(t.id)

            detected_black_boats = [
                b for b in self.core_env.black_boats
                if b.active and b.id in detected_ids
            ]

            observation = AgentObservation(
                self.core_env.white_boats,
                self.core_env.all_white_drones,
                detected_black_boats,
                self.core_env.current_time
            )
            
            agent_action = self.white_agent.get_actions(observation)
            
            self.action_executor.execute_actions(
                agent_action,
                self.core_env.white_boats,
                self.core_env.all_white_drones,
                self.core_env,
                self.core_env.current_time,
                dt
            )
            
            # 记录无人机起飞事件 (在动作执行后)
            for drone in self.core_env.all_white_drones:
                if (drone.active and (getattr(drone, 'state', None) in ['flying', 'returning']) and 
                    drone.id not in self.event_tracker.drone_launch_times):
                    self.event_tracker.log_event(
                        self.core_env.current_time,
                        'drone_launch',
                        {'drone_id': drone.id, 'parent_boat': drone.parent_boat_id}
                    )
            
            # 记录无人机降落事件 (在动作执行后)
            for drone in self.core_env.all_white_drones:
                if (drone.docked_on_boat_id is not None and 
                    drone.id in self.event_tracker.drone_launch_times and
                    drone.id not in self.event_tracker.drone_landing_times):
                    flight_time = self.core_env.current_time - self.event_tracker.drone_launch_times[drone.id]
                    self.event_tracker.log_event(
                        self.core_env.current_time,
                        'drone_landing',
                        {
                            'drone_id': drone.id,
                            'flight_time': flight_time,
                            'energy_remaining': drone.energy
                        }
                    )
            
            # 4. 更新黑方单位
            if not self.using_test_case:
                self.black_agent.update_all_black_boats(
                    self.core_env.black_boats,
                    self.core_env.white_boats,
                    self.core_env.current_time,
                    dt
                )
            else:
                # 在测试集模式下，这个方法不会被调用
                pass
            
            # 5. 更新核心环境
            prev_intercepted = self.core_env.intercepted_black_boats
            prev_collision_count = self.core_env.collision_count
            
            self.core_env.update(dt)
            
            # 记录拦截事件
            newly_intercepted_count = self.core_env.intercepted_black_boats - prev_intercepted
            if newly_intercepted_count > 0:
                self.event_tracker.log_event(
                    self.core_env.current_time,
                    'interception',
                    {'count': newly_intercepted_count, 'total': self.core_env.intercepted_black_boats}
                )
                if self.verbose:
                    print(f"[{self.core_env.current_time:.1f}s] 拦截事件: +{newly_intercepted_count} (总计: {self.core_env.intercepted_black_boats})")
                
                # 推断是否为无人机拦截
                flying_drones = [d for d in self.core_env.all_white_drones if d.active and (getattr(d, 'state', None) in ['flying', 'returning'])]
                if flying_drones:
                    # 简化逻辑：只要有拦截发生且有无人机在天上，就记为无人机拦截贡献
                    # 更精确的判断需要核心层支持，这里作为近似统计
                    self.event_tracker.log_event(
                        self.core_env.current_time,
                        'drone_interception',
                        {'count': newly_intercepted_count}
                    )

            # 记录碰撞事件
            if self.core_env.collision_count > prev_collision_count:
                new_collisions = self.core_env.collision_count - prev_collision_count
                self.event_tracker.log_event(
                    self.core_env.current_time,
                    'collision',
                    {'count': new_collisions, 'total': self.core_env.collision_count}
                )
                if self.verbose:
                    print(f"[{self.core_env.current_time:.1f}s] 碰撞事件: +{new_collisions} (总计: {self.core_env.collision_count})")
            
            # 检查游戏结束
            game_over, winner = self.core_env.is_game_over()
            if game_over:
                break
            
            self.total_steps += 1
            
            # 定期输出进度
            if self.verbose and self.total_steps % 1000 == 0:
                active_black = len([b for b in self.core_env.black_boats if b.active])
                crossed_black = len([b for b in self.core_env.black_boats if b.x > 0])
                print(f"[{self.core_env.current_time:.1f}s] 步数: {self.total_steps}, "
                      f"黑方剩余: {active_black}, 突破: {crossed_black}, "
                      f"拦截: {self.core_env.intercepted_black_boats}")
        
        # 游戏结束，计算结果
        end_time = time.time()
        game_stats = self.core_env.get_game_state()
        
        result = {
            'winner': winner if self.total_steps < self.max_steps else 'timeout',
            'duration': self.core_env.current_time,
            'steps': self.total_steps,
            'real_time': end_time - start_time,
            'initial_black_boats': initial_black_count,
            'final_stats': game_stats,
            'event_summary': self.event_tracker.get_summary(),
            'key_events': {
                'detections': len(self.event_tracker.detection_events),
                'interceptions': len(self.event_tracker.interception_events),
                'collisions': len(self.event_tracker.collision_events),
                'drone_missions': len(self.event_tracker.drone_launch_times)
            }
        }
        
        return result
    
    # ===== 测试集支持 =====
    def run_single_game_for_case(self, case_cfg: Dict[str, Any]) -> Dict[str, Any]:
        """按测试集用例运行单局游戏并返回结果（无可视化）"""
        # 设置黑方数量并重置环境
        GameConfig.BLACK_BOATS = case_cfg.get('black_boat_count', GameConfig.BLACK_BOATS)
        start_time = time.time()
        
        self.core_env.reset()
        self.white_agent.reset()
        self.event_tracker = GameEventTracker()
        self.total_steps = 0
        
        # 基于测试集的黑方智能体
        tc_black_agent = TestCaseBlackAgent(case_cfg)
        tc_black_agent.reset()
        tc_black_agent.initialize_paths(self.core_env.black_boats)
        self.using_test_case = True
        
        if self.verbose:
            print(f"\n=== 开始新游戏 - {self.agent_type} | 测试用例: {case_cfg.get('case_name', '未命名')} ===")
            print(f"白方无人艇: {len(self.core_env.white_boats)}艘")
            print(f"黑方无人艇: {len(self.core_env.black_boats)}艘")
            print("-" * 50)
        
        initial_black_count = len([b for b in self.core_env.black_boats if b.active])
        winner = 'timeout'
        
        while self.total_steps < self.max_steps:
            dt = GameConfig.TIME_STEP
            
            # 探测与记录
            self.core_env.update_detection_system()
            all_detected_ids = set()
            for boat in self.core_env.white_boats:
                if boat.active:
                    for target in boat.detected_targets:
                        if target.active:
                            all_detected_ids.add(target.id)
            for drone in self.core_env.all_white_drones:
                if drone.active and (getattr(drone, 'state', None) in ['flying', 'returning']):
                    for target in drone.detected_targets:
                        if target.active:
                            all_detected_ids.add(target.id)
            if all_detected_ids:
                self.event_tracker.log_event(self.core_env.current_time, 'detection', {'detected_black_boats': list(all_detected_ids)})
            
            # 白方决策
            detected_ids = set()
            for boat in self.core_env.white_boats:
                for t in boat.detected_targets:
                    if t.active:
                        detected_ids.add(t.id)
            for drone in self.core_env.all_white_drones:
                for t in drone.detected_targets:
                    if t.active:
                        detected_ids.add(t.id)
            detected_black_boats = [b for b in self.core_env.black_boats if b.active and b.id in detected_ids]
            observation = AgentObservation(
                self.core_env.white_boats,
                self.core_env.all_white_drones,
                detected_black_boats,
                self.core_env.current_time
            )
            agent_action = self.white_agent.get_actions(observation)
            self.action_executor.execute_actions(
                agent_action,
                self.core_env.white_boats,
                self.core_env.all_white_drones,
                self.core_env,
                self.core_env.current_time,
                dt
            )
            
            # 无人机起降记录
            for drone in self.core_env.all_white_drones:
                if (drone.active and (getattr(drone, 'state', None) in ['flying', 'returning']) and 
                    drone.id not in self.event_tracker.drone_launch_times):
                    self.event_tracker.log_event(self.core_env.current_time, 'drone_launch', {'drone_id': drone.id, 'parent_boat': drone.parent_boat_id})
            for drone in self.core_env.all_white_drones:
                if (drone.docked_on_boat_id is not None and 
                    drone.id in self.event_tracker.drone_launch_times and
                    drone.id not in self.event_tracker.drone_landing_times):
                    flight_time = self.core_env.current_time - self.event_tracker.drone_launch_times[drone.id]
                    self.event_tracker.log_event(self.core_env.current_time, 'drone_landing', {'drone_id': drone.id, 'flight_time': flight_time, 'energy_remaining': drone.energy})
            
            # 测试集黑方更新（路径跟踪+锁定尝试）
            tc_black_agent.update_all_black_boats(self.core_env, dt)
            
            # 环境推进与事件
            prev_intercepted = self.core_env.intercepted_black_boats
            prev_collision_count = self.core_env.collision_count
            self.core_env.update(dt)
            newly_intercepted_count = self.core_env.intercepted_black_boats - prev_intercepted
            if newly_intercepted_count > 0:
                self.event_tracker.log_event(self.core_env.current_time, 'interception', {'count': newly_intercepted_count, 'total': self.core_env.intercepted_black_boats})
                if self.verbose:
                    print(f"[{self.core_env.current_time:.1f}s] 拦截事件: +{newly_intercepted_count} (总计: {self.core_env.intercepted_black_boats})")
                flying_drones = [d for d in self.core_env.all_white_drones if d.active and d.docked_on_boat_id is None]
                if flying_drones:
                    self.event_tracker.log_event(self.core_env.current_time, 'drone_interception', {'count': newly_intercepted_count})
            if self.core_env.collision_count > prev_collision_count:
                new_collisions = self.core_env.collision_count - prev_collision_count
                self.event_tracker.log_event(self.core_env.current_time, 'collision', {'count': new_collisions, 'total': self.core_env.collision_count})
                if self.verbose:
                    print(f"[{self.core_env.current_time:.1f}s] 碰撞事件: +{new_collisions} (总计: {self.core_env.collision_count})")
            
            # 结束判定
            game_over, winner = self.core_env.is_game_over()
            if game_over:
                break
            self.total_steps += 1
            if self.verbose and self.total_steps % 1000 == 0:
                active_black = len([b for b in self.core_env.black_boats if b.active])
                crossed_black = len([b for b in self.core_env.black_boats if b.x > 0])
                print(f"[{self.core_env.current_time:.1f}s] 步数: {self.total_steps}, 黑方剩余: {active_black}, 突破: {crossed_black}, 拦截: {self.core_env.intercepted_black_boats}")
        
        end_time = time.time()
        game_stats = self.core_env.get_game_state()
        result = {
            'winner': winner if self.total_steps < self.max_steps else 'timeout',
            'duration': self.core_env.current_time,
            'steps': self.total_steps,
            'real_time': end_time - start_time,
            'initial_black_boats': initial_black_count,
            'final_stats': game_stats,
            'event_summary': self.event_tracker.get_summary(),
            'key_events': {
                'detections': len(self.event_tracker.detection_events),
                'interceptions': len(self.event_tracker.interception_events),
                'collisions': len(self.event_tracker.collision_events),
                'drone_missions': len(self.event_tracker.drone_launch_times)
            },
            'case_name': case_cfg.get('case_name', '未命名')
        }
        
        # 复位标记
        self.using_test_case = False
        return result
    
    def run_batch_cases(self, cases: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """按测试集用例批量运行"""
        results: List[Dict[str, Any]] = []
        if not self.summary_only:
            print(f"开始测试集批量测试 - 共 {len(cases)} 个用例")
            print(f"使用智能体: {self.agent_type}")
            print("="*60)
        
        for i, case in enumerate(cases):
            if not self.summary_only:
                print(f"\n>>> 用例 {i+1}/{len(cases)}: {case.get('case_name', '未命名')}")
            if self.summary_only:
                with contextlib.redirect_stdout(io.StringIO()):
                    res = self.run_single_game_for_case(case)
                self._print_key_summary(res)
            else:
                res = self.run_single_game_for_case(case)
                if self.verbose:
                    self.print_game_result(res)
            results.append(res)
        
        if len(results) > 1 and not self.summary_only:
            self._print_batch_summary(results)
        return results
    
    def print_game_result(self, result: Dict[str, Any]):
        """打印游戏结果"""
        print(f"\n{'='*60}")
        title_suffix = f" | 测试用例: {result['case_name']}" if 'case_name' in result else ""
        print(f"游戏结果摘要 - {self.agent_type}{title_suffix}")
        print(f"{'='*60}")
        
        # 基本信息
        winner_text = {
            'white_wins': '白方胜利',
            'black_wins': '黑方胜利',
            'timeout': '超时结束'
        }.get(result['winner'], '未知结果')
        
        print(f"胜负结果: {winner_text}")
        print(f"游戏时长: {result['duration']:.1f} 秒")
        print(f"仿真步数: {result['steps']:,} 步")
        print(f"实际耗时: {result['real_time']:.2f} 秒")
        
        # 战斗统计
        stats = result['final_stats']
        print(f"\n战斗统计:")
        print(f"  初始黑方无人艇: {result['initial_black_boats']} 艘")
        print(f"  黑方突破防线: {stats['crossed_black_boats']} 艘")
        print(f"  白方成功拦截: {stats['intercepted_black_boats']} 艘")
        print(f"  碰撞摧毁: {result['key_events']['collisions']} 次")
        print(f"  拦截成功率: {stats['intercepted_black_boats']/result['initial_black_boats']*100:.1f}%")
        
        # 无人机任务统计
        events = result['event_summary']
        print(f"\n无人机作战统计:")
        print(f"  无人机起飞次数: {events['drone_launches']} 次")
        print(f"  无人机降落次数: {events['drone_landings']} 次")
        print(f"  探测事件: {events['detections']} 次")
        print(f"  拦截成功: {events['drone_interceptions']} 次")
        
        # 效能分析
        if result['duration'] > 0:
            print(f"\n作战效能:")
            print(f"  平均拦截速度: {stats['intercepted_black_boats']/(result['duration']/60):.2f} 艘/分钟")
            print(f"  无人机利用率: {events['drone_launches']/(result['duration']/60):.2f} 次起飞/分钟")
        
        print(f"\n{'='*60}")

    def _print_key_summary(self, result: Dict[str, Any]):
        """仅打印关键统计摘要"""
        stats = result['final_stats']
        first_bt = stats.get('first_breakthrough_time')
        intercept_time_text = f"{first_bt:.1f}s" if isinstance(first_bt, (int, float)) and first_bt is not None else "N/A"
        print("\n=== 关键统计（控制台） ===")
        print(f"黑方突防成功数量: {stats.get('crossed_black_boats', 0)}")
        print(f"白方阻击时间: {intercept_time_text}")
        print(f"白方被锁定次数: {stats.get('black_lock_count', 0)}")
        print(f"黑方被锁定次数: {stats.get('white_lock_count', 0)}")
        print(f"白方发生碰撞次数: {stats.get('collision_count', 0)}")
        print("======================\n")
    
    def run_batch_games(self, num_games: int = 1) -> List[Dict[str, Any]]:
        """运行多局游戏"""
        results = []
        
        if not self.summary_only:
            print(f"开始批量测试 - 运行 {num_games} 局游戏")
            print(f"使用智能体: {self.agent_type}")
            print("="*60)
        
        for i in range(num_games):
            if not self.summary_only:
                print(f"\n>>> 第 {i+1}/{num_games} 局游戏")
            if self.summary_only:
                with contextlib.redirect_stdout(io.StringIO()):
                    result = self.run_single_game()
                self._print_key_summary(result)
            else:
                result = self.run_single_game()
                if self.verbose:
                    self.print_game_result(result)
            results.append(result)
        
        # 统计分析
        if num_games > 1 and not self.summary_only:
            self._print_batch_summary(results)
        
        return results
    
    def _print_batch_summary(self, results: List[Dict[str, Any]]):
        """打印批量测试摘要"""
        print(f"\n{'#'*60}")
        print(f"批量测试总结 ({len(results)} 局游戏)")
        print(f"{'#'*60}")
        
        # 胜率统计
        white_wins = sum(1 for r in results if r['winner'] == 'white_wins')
        black_wins = sum(1 for r in results if r['winner'] == 'black_wins')
        timeouts = sum(1 for r in results if r['winner'] == 'timeout')
        
        print(f"胜负统计:")
        print(f"  白方胜利: {white_wins} 局 ({white_wins/len(results)*100:.1f}%)")
        print(f"  黑方胜利: {black_wins} 局 ({black_wins/len(results)*100:.1f}%)")
        print(f"  超时结束: {timeouts} 局 ({timeouts/len(results)*100:.1f}%)")
        
        # 平均统计
        avg_duration = sum(r['duration'] for r in results) / len(results)
        avg_steps = sum(r['steps'] for r in results) / len(results)
        avg_intercepted = sum(r['final_stats']['intercepted_black_boats'] for r in results) / len(results)
        avg_crossed = sum(r['final_stats']['crossed_black_boats'] for r in results) / len(results)
        
        print(f"\n平均表现:")
        print(f"  游戏时长: {avg_duration:.1f} 秒")
        print(f"  仿真步数: {avg_steps:,.0f} 步")
        print(f"  拦截数量: {avg_intercepted:.1f} 艘")
        print(f"  突破数量: {avg_crossed:.1f} 艘")
        print(f"  拦截效率: {avg_intercepted/(avg_intercepted+avg_crossed)*100:.1f}%")


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='SH-15 批量游戏测试工具')
    parser.add_argument('--agent', choices=['simple', 'fsm'], default='simple',
                        help='选择白方智能体类型: simple(简单防线) 或 fsm(FSM状态机)')
    parser.add_argument('--games', type=int, default=1,
                        help='运行游戏局数 (默认: 1)')
    parser.add_argument('--quiet', action='store_true',
                        help='安静模式，减少输出信息')
    parser.add_argument('--max-steps', type=int, default=50000,
                        help='单局游戏最大步数限制 (默认: 50000)')
    parser.add_argument('--use-cases', action='store_true',
                        help='启用测试集模式，按 sh15/SH-15测试集 运行黑方路径方案')
    parser.add_argument('--test-dir', default='sh15/SH-15测试集',
                        help='测试集目录路径 (默认: sh15/SH-15测试集)')
    parser.add_argument('--case', default=None,
                        help='仅运行指定用例文件名，例如 方案3-黑方艇数量_5.json')
    parser.add_argument('--summary-only', action='store_true',
                        help='仅输出关键统计（屏蔽过程性日志，含FSM的print）')
    
    args = parser.parse_args()
    
    # 创建运行器
    use_fsm = (args.agent == 'fsm')
    runner = BatchGameRunner(use_fsm_agent=use_fsm, verbose=not args.quiet)
    runner.max_steps = args.max_steps
    runner.summary_only = args.summary_only
    
    try:
        if args.use_cases:
            # 测试集模式
            loader = TestCaseLoader(args.test_dir)
            if args.case:
                cases = [loader.load_case(args.case)]
            else:
                cases = loader.load_all_cases()
            if not runner.summary_only:
                print(f"SH-15 测试集批量测试工具")
                print(f"智能体类型: {runner.agent_type}")
                print(f"用例数量: {len(cases)}")
                print(f"最大步数: {args.max_steps}")
            start_time = time.time()
            results = runner.run_batch_cases(cases)
            total_time = time.time() - start_time
            if not runner.summary_only:
                print(f"\n测试集批量测试完成！")
                print(f"总耗时: {total_time:.2f} 秒")
                per_case = total_time/len(cases) if cases else 0.0
                print(f"平均每例: {per_case:.2f} 秒")
        else:
            # 常规定量评估
            if not runner.summary_only:
                print(f"SH-15 博弈决策模型批量测试工具")
                print(f"智能体类型: {runner.agent_type}")
                print(f"测试局数: {args.games}")
                print(f"最大步数: {args.max_steps}")
            start_time = time.time()
            results = runner.run_batch_games(args.games)
            total_time = time.time() - start_time
            if not runner.summary_only:
                print(f"\n批量测试完成！")
                print(f"总耗时: {total_time:.2f} 秒")
                print(f"平均每局: {total_time/args.games:.2f} 秒")
    except KeyboardInterrupt:
        print("\n\n用户中断测试")
    except Exception as e:
        print(f"\n测试过程中出现错误: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()
